package cloud.xiangyixiang.www.spring.boot.java.basics.controller;

import cloud.xiangyixiang.www.spring.boot.java.basics.annotations.FieldSu;
import cloud.xiangyixiang.www.spring.boot.java.basics.annotations.TableSu;
import cloud.xiangyixiang.www.spring.boot.java.basics.pojo.bo.UserBo;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

/**
 * <p>
 * JAVA Reflection 反射
 * </p>
 *
 * @author zhixinglu
 * @date 2023/9/13 15:20
 */
public class ReflectionController {

    public static void main(String[] args) {
        description();

        test1();

        test2();

        test3();

        test4();

        test5();
    }

    /**
     * 详情介绍
     */
    public static void description(){
        System.out.println("详情介绍：======================");

        System.out.println("什么时候会发生类初始化？");
        System.out.println("1. 类的主动引用（一定会发生类的初始化）");
        System.out.println("  * 当虚拟机启动，先初始化main方法所在的类；");
        System.out.println("  * new一个类的对象；");
        System.out.println("  * 调用类的静态成员（除了final常量）和静态方法；");
        System.out.println("  * 使用java.lang.reflect包的方法对类进行反射调用；");
        System.out.println("  * 当初始化一个类，如果其父类没有被初始化，则先会初始化它的父类；");
        System.out.println("2. 类的被动调用（不会发生类的初始化）");
        System.out.println("  * 当访问一个静态域时，只有真正声明这个域的类才会被初始化。如：当通过子类引用父类的静态变量，不会导致子类初始化；");
        System.out.println("  * 通过数组定义类引用，不会触发此类的初始化；");
        System.out.println("  * 引用常量不会触发此类的初始化（常量在链接阶段就存入调用类的常量池中了）；");

        System.out.println("类加载的作用：将class文件字节码内容加载到内存中，并将这些静态数据转换成方法区的运行时数据结构，然后在堆中生成一个代表这个类的java.lang.Class对象，作为方法区中类数据的访问入口。");

        System.out.println();
    }

    /**
     * 动态创建对象
     */
    private static void test1() {
        System.out.println("动态创建对象执行方法：======================");
        try {
            //获得class对象
            Class c1 = Class.forName("cloud.xiangyixiang.www.spring.boot.java.basics.pojo.bo.UserBo");
            //1、构造一个对象，本质是无参构造器
            UserBo user1 = (UserBo) c1.newInstance();
            user1.setUsername("ZhiXingLu");
            user1.setAge(1);
            System.out.println(user1);

            //2、通过构造器创建对象
            Constructor constructor = c1.getDeclaredConstructor(String.class, Integer.class);
            UserBo user2 = (UserBo) constructor.newInstance("郭一诺", 1);
            System.out.println(user2);


            //3、通过反射调用普通方法
            UserBo user3 = (UserBo) c1.newInstance();
            Method setName = c1.getDeclaredMethod("setUsername", String.class);
            //invoke激活
            setName.invoke(user3,"素小暖");
            System.out.println(user3.getUsername());

            //4、通过反射操作属性
            UserBo user4 = (UserBo) c1.newInstance();
            Field name = c1.getDeclaredField("username");
            //true：取消Java语言访问检查
            name.setAccessible(true);
            name.set(user4,"素小暖2");
            System.out.println(user4.getUsername());

        } catch (ClassNotFoundException e){
            System.out.println("class 不存在");
        } catch (IllegalAccessException | InstantiationException e) {
            System.out.println("class 实例化异常");
        } catch (InvocationTargetException e) {
            System.out.println("反射异常：" + e.getMessage());
        } catch (NoSuchMethodException e) {
            System.out.println("方法不存在：" + e.getMessage());
        } catch (NoSuchFieldException e) {
            System.out.println("属性不存在：" + e.getMessage());
        }
        System.out.println();
    }

    /**
     * 通过反射获取泛型信息
     */
    private static void test2(){
        System.out.println("通过反射获取泛型信息：================");
        try {
            Method method = ReflectionController.class.getMethod("test01", Map.class, List.class);
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            System.out.println("test01：Type");
            for (Type genericParameterType : genericParameterTypes) {
                System.out.println("***"+genericParameterType);
                if(genericParameterType instanceof ParameterizedType){
                    Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                    for (Type actualTypeArgument : actualTypeArguments) {
                        System.out.println(actualTypeArgument);
                    }
                }
            }

            method = ReflectionController.class.getMethod("test02", null);
            Type genericReturnType = method.getGenericReturnType();
            System.out.println("test02：Type");
            if(genericReturnType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println("test02,"+actualTypeArgument);
                }
            }
        } catch (NoSuchMethodException e) {
            System.out.println("方法不存在：" + e.getMessage());
        }
        System.out.println();
    }

    public void test01(Map<String,UserBo> map, List<UserBo> list){
        System.out.println("test01");
    }

    public Map<String, UserBo> test02(){
        System.out.println("test02");
        return Collections.emptyMap();
    }

    /**
     * 反射解决泛型问题
     */
    private static void test3(){
        System.out.println("反射解决泛型问题: ===============");
        try {
            List<String> list = new ArrayList<>();
            list.add("张三");
            list.add("李四");
            // list.add(28);
            // 不符合String 报错

            // 下面通过反省解决这个问题
            Class<?> clazz = list.getClass();
            Method method =  clazz.getMethod("add", Object.class);
            method.invoke(list, 28);
            System.out.println(list);
        } catch (InvocationTargetException e) {
            System.out.println("实例化失败：" + e.getMessage());
        } catch (NoSuchMethodException e) {
            System.out.println("方法名不存在：" + e.getMessage());
        } catch (IllegalAccessException e) {
            System.out.println("反射异常：" + e.getMessage());
        }
        System.out.println();
    }

    /**
     * 通过反射获取注解信息
     */
    private static void test4(){
        System.out.println("通过反射获取注解信息：=================");

        try {
            Class c1 = Class.forName("cloud.xiangyixiang.www.spring.boot.java.basics.pojo.bo.Student");

            //通过反射获取注解
            Annotation[] annotations = c1.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }

            //获得注解value的值
            TableSu tableSu = (TableSu) c1.getAnnotation(TableSu.class);
            String value = tableSu.value();
            System.out.println(value);

            //获得类指定的注解
            Field field = c1.getDeclaredField("name");
            FieldSu annotation = field.getAnnotation(FieldSu.class);
            System.out.println("属性名：" + annotation.columnName());
            System.out.println("属性类型：" + annotation.type());
            System.out.println("属性长度：" + annotation.length());
        } catch (NoSuchFieldException e) {
            System.out.println("类属性不存在：" + e.getMessage());
        } catch (ClassNotFoundException e) {
            System.out.println("类不存在：" + e.getMessage());
        }
        System.out.println();
    }

    /**
     * 通过配置文件动态调用方法
     */
    private static void test5(){
        System.out.println("通过配置文件动态调用方法: =============");

        try {
            Properties properties = new Properties();
            FileReader fileReader = new FileReader("/Users/weixin/workspace/IdeaProjects/spring-boot-learning/spring-boot-java-basics/src/main/resources/static/Class.txt");
            properties.load(fileReader);

            String className = properties.getProperty("classname");
            String methodName = properties.getProperty("methodname");

            Class<?> clazz = Class.forName(className);
            Method method = clazz.getMethod(methodName);
            method.invoke(clazz.newInstance());
        } catch (FileNotFoundException e) {
            System.out.println("类文件不存在：" + e.getMessage());
        } catch (IOException e) {
            System.out.println("类文件不存在：" + e.getMessage());
        } catch (ClassNotFoundException e) {
            System.out.println("类不存在：" + e.getMessage());
        } catch (InvocationTargetException e) {
            System.out.println("反射异常：：" + e.getMessage());
        } catch (NoSuchMethodException e) {
            System.out.println("类方法不存在：：" + e.getMessage());
        } catch (IllegalAccessException e) {
            System.out.println("实例化失败：" + e.getMessage());
        } catch (InstantiationException e) {
            System.out.println("实例化失败：" + e.getMessage());
        }


        System.out.println();
    }

}
